Huge.Hoo Devlog

Title: Transaction Isolation Level
Category: Database

트랜잭션의 격리 수준

트랜잭션의 격리 수준이란? 한문장으로 정의하기 어려운 내용이긴 하지만, 동시에 여러 트랜잭션이 처리되는 경우, 한 트랜잭션이 동시에 실행되는 다른 트랜잭션이 변경하거나 조회하는 데이터를 볼 수 있게 허용할지 결정하는 여부에 대한 내용이다. 트랜잭션 격리 수준은 총 4가지로, 아래로 갈 수록 격리수준이 낮아진다. 즉 격리수준이 가장 높은 SERIALIZABLE 일 때 동시성 이슈로부터 가장 안전하다고 생각할 수 있다.

📌 트랜잭션 격리 수준

  • SERIALIZABLE
  • REPEATABLE READ
  • READ COMMITTED
  • READ UNCOMMITTED

Serializable

Serializable 은 가장 엄격한 격리수준으로, 이름 그대로 직렬화, 즉 여러 트랜잭션을 순차적으로(직렬) 실행하기 때문에 동시성 이슈로부터 안전한 격리수준이다. 하지만 트랜잭션이 순차적으로 실행되기에 동시 처리 성능은 떨어질 수 밖에 없다. 그래서 Serializable 은 가장 안전한 동시에 성능은 떨어지는 트랜잭션 격리수준이다. 이 격리수준에선 순수한 Select 조회 작업에서도 대상 레코드에 넥스트 키 락을 읽기 잠금(공유락, Shared Lock) 으로 건다. 따라서 한 트랜잭션에서 넥스트 키 락이 걸린 레코드를 다른 트랜잭션에서는 절대 추가/수정/삭제할 수 없다.

REPEATABLE READ

일반적인 RDBMS 는 변경 전의 레코드를 Undo Log 공간에 백업해둔다. 이곳에는 변경 전/후 데이터가 모두 존재하여, 동일한 레코드에 대해 여러 버전의 데이터가 존재한다고 하여 이를 MVCC(Multi-Version Concurrency Control) 라고 부른다. MVCC 를 통해 트랜잭션이 롤백된 경우 데이터를 복원할 수 있을 뿐 아니라, 서로 다른 트랜잭션 간에 접근할 수 있는 데이터를 세밀하게 제어할 수 있다. 각각의 트랜잭션은 순차 증가하는 고유한 트랜잭션 번호가 존재하는데, 백업 레코드에는 어느 트랜잭션에 의해 백업되었는지 트랜잭션 번호를 함께 저장한다. 그리고 해당 데이터가 불필요해졌다고 판단되는 시점에 주기적으로 백그라운드 스레드를 통해 삭제한다.

Repeatable Read 는 mvcc 를 이용해 한 트랜잭션 내에서 동일한 결과를 보장하지만(동일 트랜잭션에선 동일한 결과를 읽음), 새로운 레코드가 추가되는 경우 부정합이 생길 수 있다. 일반적으로 MYSQL 의 Repeatable Read 에서는 Phantom Read 가 발생하지 않는다. 왜냐하면 Gap lock 이 존재하기 때문이다.

Read Committed

Read Committed 는 커밋된 데이터만 조회할 수 있다. 여기서는 Phantom Read 뿐 아니라 Non-Repeatable Read 문제까지 발생할 수 있다. 당연한 얘기처럼 들리는데, 여기서는 다른 트랜잭션의 커밋 여부에 따라 Non-Repeatable Read 가 발생할 수 있다. Read Committed 수준에서는 애초에 커밋된 데이터만 읽을 수 있기 때문에 트랜잭션 내에서 실행되는 SELECT 와 트랜잭션 밖에서 실행되는 SELECT 의 차이가 별로없다.

Read Uncommitted

read uncommitted 는 격리수준 최하위에 속한다. 격리수준이 최하위다? 이 말은 즉슨 동시성에 대한 제어가 거의 되지 않는다는 말과 상통한다. 정확히 말하면 해당 격리수준에선 커밋하지 않은 데이터 조차도 접근할 수 있음을 뜻한다. Read Uncommitted 에서는 다른 트랜잭션의 작업이 커밋 또는 롤백되지 않아도 즉시 보이게 된다. 예를 들어 A 트랜잭션에서 insert 할 때 해당 트랜잭션이 아직 커밋되지 않았음에도, 거의 동시에 실행되는 다른 트랜잭션에서 해당 A 의 insert 데이터를 조회할 수 있다. 만약 A 트랜잭션에서 insert 한 즉시 다른(B) 트랜잭션에서 해당 데이터를 조회했는데, A 트랜잭션이 롤백되는 경우라면 B 트랜잭션은 존재하지도 않는 데이터를 조회한 상황에 처한다.

이렇듯 어떤 트랜잭션의 작업이 아직 완료되지 않았는데도 다른 트랜잭션에서 볼 수 있는 부정합 문제를 Dirty Read 라 한다. Read Uncommitted 는 RDBMS 표준에서 인정하지 않을 정도로 정합성에 문제가 많은 격리 수준이다. 따라서 MySQL 을 사용한다면 최소 Read Committed 이상의 격리 수준을 사용해야 한다.

ref : https://mangkyu.tistory.com/300

@huge.hoo